using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Security.Claims;
using UniversalAdmin.Domain.Entities;
using UniversalAdmin.Domain.Interfaces;

namespace UniversalAdmin.Api.Filters;

public class AuditLogActionFilter : IAsyncActionFilter
{
  private readonly IUnitOfWork _uow;

  public AuditLogActionFilter(IUnitOfWork uow)
  {
    _uow = uow;
  }

  public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
  {

    if (context.ActionDescriptor.EndpointMetadata
              .OfType<SkipAuditLogAttribute>()
              .Any())
    {
      await next();   // 仅此一次
      return;
    }
    // 先执行 Action
    var executed = await next();

    // 只要没有 Exception 就记录
    if (executed.Exception == null)
    {
      var http = context.HttpContext;
      var userIdClaim = http.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
      var action = context.ActionDescriptor.RouteValues["action"];
      var controller = context.ActionDescriptor.RouteValues["controller"];

      var log = new OperationLog
      {
        UserId = int.TryParse(userIdClaim, out var uid) ? uid : null,
        Action = $"{controller}.{action}".ToLower(),
        Resource = controller,
        ResourceId = GetResourceId(executed),
        IpAddress = GetClientIpAddress(http),
        UserAgent = http.Request.Headers.UserAgent
      };

      await _uow.OperationLogRepository.AddAsync(log);
      await _uow.SaveChangesAsync();
    }
  }

  private static int? GetResourceId(ActionExecutedContext ctx)
  {
    // 优先从路由参数里拿 id
    if (ctx.Result is ObjectResult { Value: not null } or &&
        ctx.RouteData.Values.TryGetValue("id", out var rid) && int.TryParse(rid?.ToString(), out var id))
      return id;
    return null;
  }

  private static string GetClientIpAddress(HttpContext context)
  {
    // 首先检查代理头（如果通过反向代理）
    var forwardedFor = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
    if (!string.IsNullOrEmpty(forwardedFor))
    {
      // X-Forwarded-For 可能包含多个IP，取第一个
      var ip = forwardedFor.Split(',')[0].Trim();
      if (!string.IsNullOrEmpty(ip))
        return ip;
    }

    // 检查 X-Real-IP 头
    var realIp = context.Request.Headers["X-Real-IP"].FirstOrDefault();
    if (!string.IsNullOrEmpty(realIp))
      return realIp;

    // 获取远程IP地址
    var remoteIp = context.Connection.RemoteIpAddress;
    if (remoteIp != null)
    {
      // 如果是IPv6的本地环回地址，转换为IPv4
      if (remoteIp.ToString() == "::1")
        return "127.0.0.1";
      
      // 如果是IPv6地址，但不是本地环回，保持原样
      return remoteIp.ToString();
    }

    return "Unknown";
  }
}